﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;

namespace RpaDesigner.Frame
{
    public class Connector : Control, INotifyPropertyChanged
    {
        private Point? _dragStartPoint = null;

        private Point _position;

        public Point Position
        {
            get => _position;
            set
            {
                if (_position == value) return;

                _position = value;
                OnPropertyChanged(nameof(Position));
            }
        }

        public ConnectorOrientation Orientation { get; set; }

        public static readonly DependencyProperty BackgroundColorProperty =
            DependencyProperty.Register(nameof(BackgroundColor), typeof(Brush), typeof(Connector));

        public Brush BackgroundColor
        {
            get => (Brush) GetValue(BackgroundColorProperty);
            set => SetValue(BackgroundColorProperty, value);
        }


        private DesignerItem _parentDesignerItem;

        public DesignerItem ParentDesignerItem => _parentDesignerItem ??= DataContext as DesignerItem;

        private List<Connection> _connections;

        public List<Connection> Connections
        {
            get
            {
                if (_connections == null)
                    _connections = new List<Connection>();

                return _connections;
            }
        }

        public Connector()
        {
            base.LayoutUpdated += new EventHandler(Connector_LayoutUpdated);
            this.BackgroundColor = Brushes.Transparent;
        }

        void Connector_LayoutUpdated(object sender, EventArgs e)
        {
            var designer = GetDesignerCanvas(this);
            if (designer != null)
            {
                this.Position = this.TransformToAncestor(designer)
                    .Transform(new Point(this.Width / 2, this.Height / 2));
            }
        }

        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            base.OnMouseLeftButtonDown(e);

            var canvas = GetDesignerCanvas(this);

            if (canvas == null) return;

            this._dragStartPoint = e.GetPosition(canvas);
            e.Handled = true;
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            if (e.LeftButton != MouseButtonState.Pressed)
            {
                this._dragStartPoint = null;
            }

            if (this._dragStartPoint.HasValue)
            {
                var canvas = GetDesignerCanvas(this);
                if (canvas != null)
                {
                    AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(canvas);
                    if (adornerLayer != null)
                    {
                        ConnectorAdorner adorner = new ConnectorAdorner(canvas, this);
                        if (adorner != null)
                        {
                            adornerLayer.Add(adorner);
                            e.Handled = true;
                        }
                    }
                }
            }
        }

        private DesignerCanvas GetDesignerCanvas(DependencyObject element)
        {
            while (element != null && !(element is DesignerCanvas))
            {
                element = VisualTreeHelper.GetParent(element);
            }

            return element as DesignerCanvas;
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string name)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }

        #endregion

        internal ConnectorInfo GetInfo()
        {
            ConnectorInfo info = new ConnectorInfo();
            info.DesignerItemLeft = DesignerCanvas.GetLeft(this.ParentDesignerItem);
            info.DesignerItemTop = DesignerCanvas.GetTop(this.ParentDesignerItem);
            info.DesignerItemSize = new Size(this.ParentDesignerItem.ActualWidth, this.ParentDesignerItem.ActualHeight);
            info.Orientation = this.Orientation;
            info.Position = this.Position;
            return info;
        }

        internal struct ConnectorInfo
        {
            public double DesignerItemLeft { get; set; }
            public double DesignerItemTop { get; set; }
            public Size DesignerItemSize { get; set; }
            public Point Position { get; set; }
            public ConnectorOrientation Orientation { get; set; }
        }

        public enum ConnectorOrientation
        {
            None,
            Left,
            Top,
            Right,
            Bottom
        }
    }
}